/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.nanosn.framework.core;

import com.nanosn.utils.ClassFinder;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;

/**
 * TODOC
 * @author selkhateeb
 */
public final class ComponentManager
{
    // <editor-fold defaultstate="collapsed" desc="Private Members">

    /**
     * TODOC
     */
    private final HashMap<String, Component> components = new HashMap();

    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Constructors">
    /**
     * TODOC
     * Pre:
     * Post:
     */
    public ComponentManager()
    {
        LoadComponents();
    }

    public ComponentManager(String... realPaths)
    {
        LoadComponents(realPaths);
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Public Methods">
    /**
     * TODOC
     * Pre:
     * Post:
     * @return
     * @throws Exception
     */
    public final List<Component> getComponents() throws Exception
    {
        List<Component> componentInstances = new ArrayList<Component>();

        Set<String> a = this.components.keySet();
        for (String key : a)
        {
            Component c = this.components.get(key);
            if (c == null)
            {
                System.out.println(key);
                c = this.getInstance(key);
            }
            componentInstances.add(c);
        }

        return componentInstances;
    }

    /**
     * TODOC
     * Pre:
     * Post:
     * @param component
     */
    public void addComponent(Component component)
    {
        try
        {
            this.components.put(component.getClass().getName(), component);
        }
        catch (Exception ex)
        {
            Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void addComponent(String... components)
    {
        for (String component : components)
        {
            try
            {
                this.LoadComponent(Class.forName(component));
            }
            catch (ClassNotFoundException ex)
            {
                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
            }

        }


    }

    /**
     * TODOC
     * Pre:
     * Post:
     * @param classname
     * @return
     * @throws Exception
     */
    public synchronized Component getInstance(String classname) throws Exception
    {

        Component instance = null;
        instance = this.components.get(classname);
        if (instance != null)
        {
            System.out.println("No Instance of class!!!!!! How come!!");
        }
        return instance;
    }

    private void LoadComponent(Class<?> class1)
    {
        System.out.println("Found Class:  " + class1.getName());
        try
        {
            Constructor c;
            Component instance = null;
            c = class1.getConstructor(ComponentManager.class);
            instance = (Component) c.newInstance(this);
            this.addComponent(instance);
        }
        catch (InstantiationException ex)
        {
            Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (IllegalAccessException ex)
        {
            Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (IllegalArgumentException ex)
        {
            Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (InvocationTargetException ex)
        {
            Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (NoSuchMethodException ex)
        {
            Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        catch (SecurityException ex)
        {
            Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    // </editor-fold>
    // <editor-fold defaultstate="collapsed" desc="Private Methods">
    /**
     * TODOC
     * Pre:
     * Post:
     */
    private void LoadComponents()
    {
        ClassFinder finder = new ClassFinder();
        Vector<Class<?>> v = finder.findSubclasses("com.nanosn.framework.core.Component");
        //TODO: Deal with the errors
        List<Throwable> errors = finder.getErrors();
        for (Class<?> class1 : v)
        {
            try
            {
                Constructor c;
                Component instance = null;
                c = class1.getConstructor(ComponentManager.class);
                instance = (Component) c.newInstance(this);
                this.addComponent(instance);
            }
            catch (InstantiationException ex)
            {
                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            catch (IllegalAccessException ex)
            {
                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            catch (IllegalArgumentException ex)
            {
                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            catch (InvocationTargetException ex)
            {
                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            catch (NoSuchMethodException ex)
            {
                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
            }
            catch (SecurityException ex)
            {
                Logger.getLogger(ComponentManager.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void LoadComponents(String... realPaths)
    {
        ClassFinder finder = new ClassFinder(realPaths);
        Vector<Class<?>> v = finder.findSubclasses("com.nanosn.framework.core.Component");
        //TODO: Deal with the errors
        List<Throwable> errors = finder.getErrors();
        for (Throwable throwable : errors)
        {
            System.out.println("ERRRRRR::::" + throwable.getMessage());
        }
        for (Class<?> class1 : v)
        {
            LoadComponent(class1);
        }
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="NOT YET IMPLEMENTED STUFF">
    /**
     * TODOC
     * Pre:
     * Post:
     * @param component
     */
    public void disableComponent(Component component)
    {
        //TODO
        throw new NotImplementedException();
    }

    /**
     * TODOC
     * Pre:
     * Post:
     * @param component
     */
    public void enableComponent(Component component)
    {
        //TODO
        throw new NotImplementedException();
    }
    // </editor-fold>
}
